package com.dyh.quickdemozwei;

import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.function.Consumer;

@Slf4j
public class TestHashLock {

    int i1;
    int i2;
    int[] a1=new int[2];
    int i3;

    static    Unsafe U;
    static    long ABASE;//16
    static  long ASHIFT;
    static final int a;
    static {
//        a = 1;
        try {
            a = 1;
            U = reflectGetUnsafe();
//            Class K = TestHashLock.class;
//            System.out.println(U.objectFieldOffset
//                    (K.getDeclaredField("i1")));
//            System.out.println(U.objectFieldOffset
//                    (K.getDeclaredField("i2")));
//            System.out.println(U.objectFieldOffset
//                    (K.getDeclaredField("a1")));
//            System.out.println(U.objectFieldOffset
//                    (K.getDeclaredField("i3")));
            Class<?> ak = int[].class;
            ABASE = U.arrayBaseOffset(ak);
            System.out.println("ABASE="+ABASE);

            int scale = U.arrayIndexScale(ak);//4
            System.out.println("scale="+scale);

            System.out.println("Integer.numberOfLeadingZeros(scale)="+Integer.numberOfLeadingZeros(scale));
            /*29*/
            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
            System.out.println("ASHIFT="+ASHIFT);

        }catch (Exception e){
            throw new Error(e);//这里写error final才能通过
//            e.printStackTrace();
        }

    }

    public static Unsafe reflectGetUnsafe() {
        try {
            Field field =
                    Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    ThreadPoolExecutor poolExecutor;
    {
        this.poolExecutor = new ThreadPoolExecutor(3,6,
                300, TimeUnit.SECONDS,
//                new SynchronousQueue<>(),
                new LinkedBlockingQueue<>(200),
                new ThreadFactoryBuilder().setNameFormat("pool-%d").build(),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }


    int maxParallel=32;
    int[] locks = new int[maxParallel];

    @Test public void test2(){
        List<String> orderIds = Lists.newArrayList(
                "2670485907041604565",
                "2670485907041604564",
                "2670485907041604565",
                "2670485943003675153"
//                "2668298220882048240"
        );


        List<Future> futures=new ArrayList<>();
        for (String orderId : orderIds) {
            futures.add(poolExecutor.submit(()->{
                withLockConsumer.accept(orderId);
            }) );
        }

        for (int i=futures.size()-1;i>=0;i--){
            try {
                futures.get(i).get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }


    }



    Consumer<String> originConsumer = e->{
        log.info("{} 开始消费-{}",Thread.currentThread().getName(),e);
        try {

            Thread.sleep(1000L);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        log.info("{} 结束消费-{}",Thread.currentThread().getName(),e);
    };

    Consumer<String> withLockConsumer = e->{
        log.info("{} 开始获取锁 {}",Thread.currentThread().getName(),e);
        int idef = Thread.currentThread().hashCode();
        int index = updatedHash(e) &( maxParallel-1);

        //有可能卡在这里 永远看不到别人最新的值
//        for (;;){
//            int owner = locks[index];
//            if (owner==0)
//                break;
//        }
//
        long offset =         ((long)index << ASHIFT) + ABASE;

//        for (;;){
        //提前释放bug 一开始两个线程都看到是0 一个还没释放 另一个就cas成功
//           if (U.compareAndSwapInt(locks,offset,0,idef))
//               break;
//        }


        for (;;){
            int lockOwner = locks[index];
            if (lockOwner ==idef)
                break;
            if (lockOwner!=0){//有可能一直看到owner是别人 即使别人释放了
                lockOwner = U.getIntVolatile(locks,offset);
                if (lockOwner!=0)//的确是被别人持有
                    continue;

            }
            if (U.compareAndSwapInt(locks,offset,0,idef))
               break;
        }


        log.info("{} 成功获取锁 {}",Thread.currentThread().getName(),e);

        originConsumer.accept(e);

        U.compareAndSwapInt(locks,offset,idef,0);
        log.info("{} 成功释放锁 {}",Thread.currentThread().getName(),e);

    };


//    @Test
//    public void test1(){
//
//        List<String> orderIds = Lists.newArrayList(
//                "2670485907041604565",
//                "2670485907041604564",
//                "2670485943003675153",
//                "2668298220882048240"
//        );
//
//        byte[] tags = new byte[32];
//
//
//
//        for (String orderId : orderIds) {
//            log.info("orderId:{} hash={} idfHash={} updatedHash={}",
//                    orderId,orderId.hashCode(),
//                    System.identityHashCode(orderId),
//                    updatedHash(orderId)
//            );
//        }
//
//        System.out.println();
//
//
//    }

    int updatedHash(String str){
        int h;
        return (h=str.hashCode())& h>>>16;
    }
}
